From d366b69d6ad3d584408c253d3d52398c3d5c48b3 Mon Sep 17 00:00:00 2001 From: "Ian.Campbell@xensource.com" Date: Thu, 6 Apr 2006 12:03:53 +0100 Subject: [PATCH] Add new hypercall "set_callback" taking a callback identifier and the callback address. This new hypercall incorporates the functionality of the existing set_callbacks hypercall in a more flexible manner. set_callbacks is retained for compatibility. Signed-off-by: Ian Campbell --- .../include/asm-i386/mach-xen/asm/hypercall.h | 8 ++ .../asm-i386/mach-xen/setup_arch_post.h | 15 ++- .../asm-x86_64/mach-xen/asm/hypercall.h | 7 ++ .../asm-x86_64/mach-xen/setup_arch_post.h | 21 +++- xen/arch/x86/x86_32/entry.S | 2 + xen/arch/x86/x86_32/traps.c | 102 ++++++++++++++++-- xen/arch/x86/x86_64/entry.S | 2 + xen/arch/x86/x86_64/traps.c | 102 +++++++++++++++++- xen/include/public/arch-x86_32.h | 5 + xen/include/public/arch-x86_64.h | 2 + xen/include/public/callback.h | 57 ++++++++++ xen/include/public/xen.h | 1 + 12 files changed, 303 insertions(+), 21 deletions(-) create mode 100644 xen/include/public/callback.h diff --git a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypercall.h b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypercall.h index 20977d0b80..d789fa3ae0 100644 --- a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypercall.h +++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypercall.h @@ -329,6 +329,14 @@ HYPERVISOR_nmi_op( return _hypercall2(int, nmi_op, op, arg); } +static inline int +HYPERVISOR_callback_op( + int cmd, + void *arg) +{ + return _hypercall2(int, callback_op, cmd, arg); +} + #endif /* __HYPERCALL_H__ */ /* diff --git a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/setup_arch_post.h b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/setup_arch_post.h index 646cf78578..ef697fde73 100644 --- a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/setup_arch_post.h +++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/setup_arch_post.h @@ -6,6 +6,8 @@ * use of all of the static functions. **/ +#include + static char * __init machine_specific_memory_setup(void) { unsigned long max_pfn = xen_start_info->nr_pages; @@ -23,6 +25,14 @@ extern void nmi(void); static void __init machine_specific_arch_setup(void) { struct xen_platform_parameters pp; + callback_register_t event = { + .type = CALLBACKTYPE_event, + .address = { __KERNEL_CS, (unsigned long)hypervisor_callback }, + }; + callback_register_t failsafe = { + .type = CALLBACKTYPE_failsafe, + .address = { __KERNEL_CS, (unsigned long)failsafe_callback }, + }; struct xennmi_callback cb; if (xen_feature(XENFEAT_auto_translated_physmap) && @@ -32,9 +42,8 @@ static void __init machine_specific_arch_setup(void) memset(empty_zero_page, 0, sizeof(empty_zero_page)); } - HYPERVISOR_set_callbacks( - __KERNEL_CS, (unsigned long)hypervisor_callback, - __KERNEL_CS, (unsigned long)failsafe_callback); + HYPERVISOR_callback_op(CALLBACKOP_register, &event); + HYPERVISOR_callback_op(CALLBACKOP_register, &failsafe); cb.handler_address = (unsigned long)&nmi; HYPERVISOR_nmi_op(XENNMI_register_callback, &cb); diff --git a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/hypercall.h b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/hypercall.h index 6b7411f4c5..24f0762374 100644 --- a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/hypercall.h +++ b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/hypercall.h @@ -330,6 +330,13 @@ HYPERVISOR_nmi_op( return _hypercall2(int, nmi_op, op, arg); } +static inline int +HYPERVISOR_callback_op( + int cmd, void *arg) +{ + return _hypercall2(int, callback_op, cmd, arg); +} + #endif /* __HYPERCALL_H__ */ /* diff --git a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/setup_arch_post.h b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/setup_arch_post.h index 701190a49b..c48ef6cbb3 100644 --- a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/setup_arch_post.h +++ b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/setup_arch_post.h @@ -6,20 +6,33 @@ * use of all of the static functions. **/ +#include + extern void hypervisor_callback(void); extern void failsafe_callback(void); extern void nmi(void); static void __init machine_specific_arch_setup(void) { + callback_register_t event = { + .type = CALLBACKTYPE_event, + .address = (unsigned long) hypervisor_callback, + }; + callback_register_t failsafe = { + .type = CALLBACKTYPE_failsafe, + .address = (unsigned long)failsafe_callback, + }; + callback_register_t syscall = { + .type = CALLBACKTYPE_syscall, + .address = (unsigned long)system_call, + }; #ifdef CONFIG_X86_LOCAL_APIC struct xennmi_callback cb; #endif - HYPERVISOR_set_callbacks( - (unsigned long) hypervisor_callback, - (unsigned long) failsafe_callback, - (unsigned long) system_call); + HYPERVISOR_callback_op(CALLBACKOP_register, &event); + HYPERVISOR_callback_op(CALLBACKOP_register, &failsafe); + HYPERVISOR_callback_op(CALLBACKOP_register, &syscall); #ifdef CONFIG_X86_LOCAL_APIC cb.handler_address = (unsigned long)&nmi; diff --git a/xen/arch/x86/x86_32/entry.S b/xen/arch/x86/x86_32/entry.S index b19796bbac..049dc5ced5 100644 --- a/xen/arch/x86/x86_32/entry.S +++ b/xen/arch/x86/x86_32/entry.S @@ -648,6 +648,7 @@ ENTRY(hypercall_table) .long do_acm_op .long do_nmi_op .long do_arch_sched_op + .long do_callback_op /* 30 */ .rept NR_hypercalls-((.-hypercall_table)/4) .long do_ni_hypercall .endr @@ -683,6 +684,7 @@ ENTRY(hypercall_args_table) .byte 1 /* do_acm_op */ .byte 2 /* do_nmi_op */ .byte 2 /* do_arch_sched_op */ + .byte 2 /* do_callback_op */ /* 30 */ .rept NR_hypercalls-(.-hypercall_args_table) .byte 0 /* do_ni_hypercall */ .endr diff --git a/xen/arch/x86/x86_32/traps.c b/xen/arch/x86/x86_32/traps.c index 59d1a845a8..f0dc661821 100644 --- a/xen/arch/x86/x86_32/traps.c +++ b/xen/arch/x86/x86_32/traps.c @@ -14,6 +14,8 @@ #include #include +#include + /* All CPUs have their own IDT to allow int80 direct trap. */ idt_entry_t *idt_tables[NR_CPUS] = { 0 }; @@ -315,20 +317,102 @@ void init_int80_direct_trap(struct vcpu *v) set_int80_direct_trap(v); } +static long register_guest_callback(struct callback_register *reg) +{ + long ret = 0; + struct vcpu *v = current; + + if ( reg->address.cs ) + fixup_guest_code_selector(reg->address.cs); + + switch ( reg->type ) + { + case CALLBACKTYPE_event: + v->arch.guest_context.event_callback_cs = reg->address.cs; + v->arch.guest_context.event_callback_eip = reg->address.eip; + break; + + case CALLBACKTYPE_failsafe: + v->arch.guest_context.failsafe_callback_cs = reg->address.cs; + v->arch.guest_context.failsafe_callback_eip = reg->address.eip; + break; + + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static long unregister_guest_callback(struct callback_unregister *unreg) +{ + long ret; + + switch ( unreg->type ) + { + default: + ret = -EINVAL; + break; + } + return ret; +} + + +long do_callback_op(int cmd, GUEST_HANDLE(void) arg) +{ + long ret; + + switch ( cmd ) + { + case CALLBACKOP_register: + { + struct callback_register reg; + + ret = -EFAULT; + if ( copy_from_guest( ®, arg, 1 ) ) + break; + + ret = register_guest_callback(®); + } + break; + + case CALLBACKOP_unregister: + { + struct callback_unregister unreg; + + ret = -EFAULT; + if ( copy_from_guest( &unreg, arg, 1 ) ) + break; + + ret = unregister_guest_callback(&unreg); + } + break; + + default: + ret = -EINVAL; + break; + } + + return ret; +} + long do_set_callbacks(unsigned long event_selector, unsigned long event_address, unsigned long failsafe_selector, unsigned long failsafe_address) { - struct vcpu *d = current; - - fixup_guest_code_selector(event_selector); - fixup_guest_code_selector(failsafe_selector); - - d->arch.guest_context.event_callback_cs = event_selector; - d->arch.guest_context.event_callback_eip = event_address; - d->arch.guest_context.failsafe_callback_cs = failsafe_selector; - d->arch.guest_context.failsafe_callback_eip = failsafe_address; + struct callback_register event = { + .type = CALLBACKTYPE_event, + .address = { event_selector, event_address }, + }; + struct callback_register failsafe = { + .type = CALLBACKTYPE_failsafe, + .address = { failsafe_selector, failsafe_address }, + }; + + register_guest_callback(&event); + register_guest_callback(&failsafe); return 0; } diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S index 6176188a85..622ca4d7cc 100644 --- a/xen/arch/x86/x86_64/entry.S +++ b/xen/arch/x86/x86_64/entry.S @@ -557,6 +557,7 @@ ENTRY(hypercall_table) .quad do_acm_op .quad do_nmi_op .quad do_arch_sched_op + .quad do_callback_op /* 30 */ .rept NR_hypercalls-((.-hypercall_table)/8) .quad do_ni_hypercall .endr @@ -592,6 +593,7 @@ ENTRY(hypercall_args_table) .byte 1 /* do_acm_op */ .byte 2 /* do_nmi_op */ .byte 2 /* do_arch_sched_op */ + .byte 2 /* do_callback_op */ /* 30 */ .rept NR_hypercalls-(.-hypercall_args_table) .byte 0 /* do_ni_hypercall */ .endr diff --git a/xen/arch/x86/x86_64/traps.c b/xen/arch/x86/x86_64/traps.c index 6794cefecf..ddf7b0aa30 100644 --- a/xen/arch/x86/x86_64/traps.c +++ b/xen/arch/x86/x86_64/traps.c @@ -17,6 +17,8 @@ #include #include +#include + void show_registers(struct cpu_user_regs *regs) { struct cpu_user_regs fault_regs = *regs; @@ -312,15 +314,105 @@ void __init percpu_traps_init(void) wrmsr(MSR_SYSCALL_MASK, EF_VM|EF_RF|EF_NT|EF_DF|EF_IE|EF_TF, 0U); } +static long register_guest_callback(struct callback_register *reg) +{ + long ret = 0; + struct vcpu *v = current; + + switch ( reg->type ) + { + case CALLBACKTYPE_event: + v->arch.guest_context.event_callback_eip = reg->address; + break; + + case CALLBACKTYPE_failsafe: + v->arch.guest_context.failsafe_callback_eip = reg->address; + break; + + case CALLBACKTYPE_syscall: + v->arch.guest_context.syscall_callback_eip = reg->address; + break; + + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static long unregister_guest_callback(struct callback_unregister *unreg) +{ + long ret; + + switch ( unreg->type ) + { + default: + ret = -EINVAL; + break; + } + return ret; +} + + +long do_callback_op(int cmd, GUEST_HANDLE(void) arg) +{ + long ret; + + switch ( cmd ) + { + case CALLBACKOP_register: + { + struct callback_register reg; + + ret = -EFAULT; + if ( copy_from_guest( ®, arg, 1 ) ) + break; + + ret = register_guest_callback(®); + } + break; + + case CALLBACKOP_unregister: + { + struct callback_unregister unreg; + + ret = -EFAULT; + if ( copy_from_guest( &unreg, arg, 1 ) ) + break; + + ret = unregister_guest_callback(&unreg); + } + break; + + default: + ret = -EINVAL; + break; + } + + return ret; +} + long do_set_callbacks(unsigned long event_address, unsigned long failsafe_address, unsigned long syscall_address) { - struct vcpu *d = current; - - d->arch.guest_context.event_callback_eip = event_address; - d->arch.guest_context.failsafe_callback_eip = failsafe_address; - d->arch.guest_context.syscall_callback_eip = syscall_address; + callback_register_t event = { + .type = CALLBACKTYPE_event, + .address = event_address, + }; + callback_register_t failsafe = { + .type = CALLBACKTYPE_failsafe, + .address = failsafe_address, + }; + callback_register_t syscall = { + .type = CALLBACKTYPE_syscall, + .address = syscall_address, + }; + + register_guest_callback(&event); + register_guest_callback(&failsafe); + register_guest_callback(&syscall); return 0; } diff --git a/xen/include/public/arch-x86_32.h b/xen/include/public/arch-x86_32.h index 1ae2df6f14..a723837f48 100644 --- a/xen/include/public/arch-x86_32.h +++ b/xen/include/public/arch-x86_32.h @@ -168,6 +168,11 @@ typedef struct { unsigned long pad[5]; /* sizeof(vcpu_info_t) == 64 */ } arch_vcpu_info_t; +typedef struct { + unsigned long cs; + unsigned long eip; +} xen_callback_t; + #endif /* !__ASSEMBLY__ */ /* diff --git a/xen/include/public/arch-x86_64.h b/xen/include/public/arch-x86_64.h index 98948c4ff5..d8b978436a 100644 --- a/xen/include/public/arch-x86_64.h +++ b/xen/include/public/arch-x86_64.h @@ -244,6 +244,8 @@ typedef struct { unsigned long pad; /* sizeof(vcpu_info_t) == 64 */ } arch_vcpu_info_t; +typedef unsigned long xen_callback_t; + #endif /* !__ASSEMBLY__ */ /* diff --git a/xen/include/public/callback.h b/xen/include/public/callback.h new file mode 100644 index 0000000000..479333ddb8 --- /dev/null +++ b/xen/include/public/callback.h @@ -0,0 +1,57 @@ +/****************************************************************************** + * callback.h + * + * Register guest OS callbacks with Xen. + * + * Copyright (c) 2006, Ian Campbell + */ + +#ifndef __XEN_PUBLIC_CALLBACK_H__ +#define __XEN_PUBLIC_CALLBACK_H__ + +#include "xen.h" + +/* + * Prototype for this hypercall is: + * long callback_op(int cmd, void *extra_args) + * @cmd == CALLBACKOP_??? (callback operation). + * @extra_args == Operation-specific extra arguments (NULL if none). + */ + +#define CALLBACKTYPE_event 0 +#define CALLBACKTYPE_failsafe 1 +#define CALLBACKTYPE_syscall 2 /* x86_64 only */ + +/* + * Register a callback. + */ +#define CALLBACKOP_register 0 +typedef struct callback_register { + int type; + xen_callback_t address; +} callback_register_t; +DEFINE_GUEST_HANDLE(callback_register_t); + +/* + * Unregister a callback. + * + * Not all callbacks can be unregistered. -EINVAL will be returned if + * you attempt to unregister such a callback. + */ +#define CALLBACKOP_unregister 1 +typedef struct callback_unregister { + int type; +} callback_unregister_t; +DEFINE_GUEST_HANDLE(callback_unregister_t); + +#endif /* __XEN_PUBLIC_CALLBACK_H__ */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/public/xen.h b/xen/include/public/xen.h index 1da6ede005..8dba3ad541 100644 --- a/xen/include/public/xen.h +++ b/xen/include/public/xen.h @@ -60,6 +60,7 @@ #define __HYPERVISOR_acm_op 27 #define __HYPERVISOR_nmi_op 28 #define __HYPERVISOR_sched_op 29 +#define __HYPERVISOR_callback_op 30 /* * VIRTUAL INTERRUPTS -- 2.30.2